package frame

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

type TokenData struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
	Exp  int    `json:"exp"`
}

// json转成结构体
func JsonToStruct(tokenString string, v any) error {
	err := json.Unmarshal([]byte(tokenString), &v)
	if err != nil {
		return fmt.Errorf("failed to unmarshal token: %w", err)
	}
	return nil
}

// 结构体和map转成json
func MapToJSON(data map[string]any) (string, error) {
	jsonData, err := json.Marshal(data)
	if err != nil {
		return "", err
	}
	return string(jsonData), nil
}

// NewToken 生成新的Token值
// payload - 负载数据
// expiresIn - 过期时间字符串格式（支持s/m/h/d/w/y单位）
// secret - 密钥，默认为配置中的密钥
func NewToken(payload map[string]any, expiresIn string, secrets ...string) (string, error) {
	secret := Config.Server.Token_secret_key // 默认值
	if len(secrets) > 0 {
		secret = secrets[0] // 使用传入的 secret
	}

	// 解析过期时间
	expiry, err := parseExpiresIn(expiresIn)
	if err != nil {
		return "", fmt.Errorf("invalid expiresIn format: %v", err)
	}

	// 创建claims，复制payload
	claims := jwt.MapClaims{}
	for k, v := range payload {
		claims[k] = v
	}
	claims["exp"] = time.Now().Add(expiry).Unix()

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString([]byte(secret))
}

// TokenVerify 验证Token值是否有效
func TokenVerify(tokenString string, secrets ...string) (jwt.MapClaims, error) {
	secret := Config.Server.Token_secret_key // 默认值
	if len(secrets) > 0 {
		secret = secrets[0] // 使用传入的 secret
	}

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(secret), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token")
}

// TokenDecode 解码Token值(不管是否过期)
func TokenDecode(tokenString string, secrets ...string) (jwt.MapClaims, error) {
	secret := Config.Server.Token_secret_key // 默认值
	if len(secrets) > 0 {
		secret = secrets[0] // 使用传入的 secret
	}

	// 先尝试正常验证
	claims, err := TokenVerify(tokenString, secret)
	if err == nil {
		return claims, nil
	}

	// 如果是过期错误，尝试解码
	if errors.Is(err, jwt.ErrTokenExpired) {
		parser := jwt.NewParser()
		token, _, decodeErr := parser.ParseUnverified(tokenString, jwt.MapClaims{})
		if decodeErr != nil {
			return nil, decodeErr
		}

		if claims, ok := token.Claims.(jwt.MapClaims); ok {
			return claims, nil
		}
	}

	// 其他错误直接返回
	return nil, err
}

// parseExpiresIn
func parseExpiresIn(expiresIn string) (time.Duration, error) {
	if expiresIn == "" {
		return time.Hour, nil // 默认1小时
	}

	// 获取数字部分和单位
	unit := expiresIn[len(expiresIn)-1:]
	valueStr := expiresIn[:len(expiresIn)-1]

	var value time.Duration
	_, err := fmt.Sscanf(valueStr, "%d", &value)
	if err != nil {
		return 0, err
	}

	switch strings.ToLower(unit) {
	case "s":
		return value * time.Second, nil
	case "m":
		return value * time.Minute, nil
	case "h":
		return value * time.Hour, nil
	case "d":
		return value * 24 * time.Hour, nil
	case "w":
		return value * 7 * 24 * time.Hour, nil
	case "y":
		return value * 365 * 24 * time.Hour, nil
	default:
		return 0, fmt.Errorf("unknown time unit: %s", unit)
	}
}
